package com.snail.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.snail.common.core.constant.CommonConstants;
import com.snail.common.core.utils.StringUtils;
import com.snail.common.core.web.page.PageResult;
import com.snail.common.lock.Lock;
import com.snail.common.security.utils.SecurityUtils;
import com.snail.workflow.api.constant.WorkflowConstants;
import com.snail.workflow.api.domain.dto.*;
import com.snail.workflow.api.domain.entity.WorkflowBusiness;
import com.snail.workflow.api.query.FlowTaskQuery;
import com.snail.workflow.config.CustomProcessDiagramGenerator;
import com.snail.workflow.exception.WorkflowException;
import com.snail.workflow.factory.FlowServiceFactory;
import com.snail.workflow.service.IFlowInstanceService;
import com.snail.workflow.service.IFlowTaskService;
import com.snail.workflow.service.IWorkflowBusinessService;
import com.snail.workflow.service.IWorkflowService;
import com.snail.workflow.utils.WorkflowUtils;
import org.flowable.bpmn.model.*;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.CommentEntity;
import org.flowable.engine.impl.persistence.entity.CommentEntityImpl;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.HistoricTaskInstanceEntityImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;

/**
 * @Description: 流程任务业务实现
 * @Author: Snail
 * @CreateDate: 2022/7/26 15:47
 * @Version: V1.0
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class WorkflowServiceImpl extends FlowServiceFactory implements IWorkflowService {

    @Autowired
    private IWorkflowBusinessService workflowBusinessService;

    @Autowired
    private IFlowInstanceService flowInstanceService;

    @Autowired
    private IFlowTaskService flowTaskService;

    @Autowired
    private Lock lock;

    /**
     * 启动流程任务
     *
     * @param taskInitWorkflowDto 流程任务对象
     * @return 成功/失败
     */
    @Override
    public WorkflowDto initWorkflow(TaskInitWorkflowDto taskInitWorkflowDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.BIZ_LOCK_KEY, taskInitWorkflowDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }

        try {
            //获取流程任务业务数据
            WorkflowBusiness workflowBusiness = getWorkflowBusiness(taskInitWorkflowDto);
            //查询当前任务
            Task task = taskService.createTaskQuery()
                    .taskAssignee(taskInitWorkflowDto.getUserId())
                    .processInstanceId(workflowBusiness.getInstanceId())
                    .singleResult();
            if (task == null) {
                throw new WorkflowException("不存在你的任务!");
            }
            //设置流程参数
            setTaskParam(task.getId(), taskInitWorkflowDto.getVariables(), WorkflowConstants.TASK_TYPE_SUBMIT);
            //返回数据
            WorkflowDto dto = buildWorkflowDto(task, workflowBusiness);
            // 可处理类型
            dto.setHandleTypes(getTaskHandleType(task, workflowBusiness));
            return dto;
        } catch (Exception e) {
            throw new WorkflowException(e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    /**
     * 获取业务流程数据没有就启动流程任务
     *
     * @param taskInitWorkflowDto 初始化参数
     * @return 结果
     */
    private WorkflowBusiness getWorkflowBusiness(TaskInitWorkflowDto taskInitWorkflowDto) {
        //1.判断流程是否启动
        WorkflowBusiness workflowBusiness = workflowBusinessService.getWorkflowBusinessByBizId(taskInitWorkflowDto.getBizId());
        //已经初始化过流程
        if (workflowBusiness != null) {
            return workflowBusiness;
        }
        //根据流程定义key启动流程
        ProcessInstance instance = flowInstanceService.startWorkflowInstanceByDefKey(taskInitWorkflowDto);
        //3.保存流程表单
        workflowBusiness = new WorkflowBusiness();
        BeanUtils.copyProperties(taskInitWorkflowDto, workflowBusiness);
        workflowBusiness.setInstanceId(instance.getProcessInstanceId());
        workflowBusiness.setCreateUserId(SecurityUtils.getUserId());
        workflowBusiness.setCreateUserName(SecurityUtils.getSysUser().getNickName());
        workflowBusiness.setCreateDeptName(SecurityUtils.getSysDept().getDeptFullName());
        workflowBusiness.setProcDefId(instance.getProcessDefinitionId());
        workflowBusiness.setProcDefKey(instance.getProcessDefinitionKey());
        workflowBusiness.setProcDefName(instance.getProcessDefinitionName());
        //待办访问的地址
        String url = taskInitWorkflowDto.getBizUrl() + "?id=" + taskInitWorkflowDto.getBizId();
        workflowBusiness.setBizUrl(url);
        workflowBusinessService.createWorkflowBusiness(workflowBusiness);
        return workflowBusiness;
    }

    /**
     * 初始化流程提交参数
     *
     * @param taskInitNextDto 查询参数
     * @return 流程参数
     */
    @Override
    public TaskParamDto initNextNode(TaskInitNextDto taskInitNextDto) {
        //返回下一任务节点参数
        TaskParamDto dto = new TaskParamDto();
        //获取当前任务
        Task task = taskService.createTaskQuery()
                .taskId(taskInitNextDto.getTaskId())
                .taskAssignee(taskInitNextDto.getUserId())
                .singleResult();
        if (task == null) {
            throw new WorkflowException("不存在你的任务!");
        }
        dto.setTaskId(task.getId());
        dto.setInstanceId(task.getProcessInstanceId());
        dto.setUserId(task.getAssignee());
        dto.setBizId(taskInitNextDto.getBizId());
        dto.setNodeKey(task.getTaskDefinitionKey());
        dto.setNodeName(task.getName());
        //常用审批意见
        dto.setTaskContexts(flowTaskService.getCommonUseComment(taskInitNextDto.getUserId(), taskInitNextDto.getType()));
        //如果是委托任务提交需要回到原来节点
        Map<String, Object> variables = taskService.getVariables(task.getId());
        if (WorkflowUtils.delegateTask(task, variables)) {
            TaskNextNodeDto taskNextNodeDto = new TaskNextNodeDto();
            taskNextNodeDto.setNextNodeKey(task.getTaskDefinitionKey());
            taskNextNodeDto.setNextNodeName(task.getName());
            taskNextNodeDto.setUserIds(Collections.singletonList(task.getOwner()));
            taskNextNodeDto.setDefaultApprove(CommonConstants.YES);
            dto.setNextNodes(Collections.singletonList(taskNextNodeDto));
            return dto;
        }
        //取消
        if (WorkflowConstants.TASK_TYPE_CANCEL.equals(taskInitNextDto.getType())) {
            return dto;
        }
        //2.获取下一任务节点
        List<TaskNextNodeDto> nextNodeDtoList = flowTaskService.getNextNode(task, taskInitNextDto.getType());
        dto.setNextNodes(nextNodeDtoList);

        return dto;
    }

    /**
     * 流程任务提交
     *
     * @param taskSubmitDto 流程提交参数
     * @return 成功/失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDto submitTask(TaskSubmitDto taskSubmitDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.TASK_LOCK_KEY, taskSubmitDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }

        //业务流程数据
        WorkflowBusiness workflowBusiness = this.workflowBusinessService.getWorkflowBusinessByBizId(taskSubmitDto.getBizId());
        try {
            //获取当前任务
            Task task = taskService.createTaskQuery()
                    .taskId(taskSubmitDto.getTaskId())
                    .taskAssignee(taskSubmitDto.getUserId())
                    .processInstanceId(taskSubmitDto.getInstanceId())
                    .singleResult();
            //校验数据
            checkData(task, taskSubmitDto);
            //设置任务参数
            Map<String, Object> variables = setTaskParam(task.getId(), taskSubmitDto.getVariables(), WorkflowConstants.TASK_TYPE_SUBMIT);
            //处理任务
            submitWorkflow(task, taskSubmitDto, WorkflowConstants.TASK_TYPE_SUBMIT);
            if (WorkflowConstants.STATUS_DRAFT.equals(workflowBusiness.getWorkflowStatus())) {
                workflowBusiness.setWorkflowStatus(WorkflowConstants.STATUS_IN_PROCESS);
            }
            if (CommonConstants.YES.equals(taskSubmitDto.getIsEndNode())) {
                BpmnModel bpmnModel = repositoryService.getBpmnModel(workflowBusiness.getProcDefId());
                FlowElement flowElement = WorkflowUtils.getFlowElement(task.getTaskDefinitionKey(), bpmnModel);
                //判断会签是否结束
                boolean isComplete = WorkflowUtils.checkMultiComplete(flowElement, variables);
                workflowBusiness.setWorkflowStatus(isComplete ? WorkflowConstants.STATUS_COMPLETE : workflowBusiness.getWorkflowStatus());
            }
            //更新业务流程数据
            this.workflowBusinessService.updateWorkflowBusiness(workflowBusiness);
            // 返回数据
            return buildWorkflowDto(task, workflowBusiness);
        } catch (Exception e) {
            throw new WorkflowException("流程提交失败:" + e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    /**
     * 封装流程信息
     *
     * @param task             流程任务
     * @param workflowBusiness 业务流程数据
     * @return 结果
     */
    private WorkflowDto buildWorkflowDto(Task task, WorkflowBusiness workflowBusiness) {
        WorkflowDto dto = new WorkflowDto();
        dto.setBizId(workflowBusiness.getBizId());
        dto.setInstanceId(workflowBusiness.getInstanceId());
        dto.setWorkflowStatus(workflowBusiness.getWorkflowStatus());
        dto.setTaskId(task.getId());
        dto.setTaskNodeId(task.getTaskDefinitionKey());
        dto.setTaskNodeName(task.getName());
        return dto;
    }

    /**
     * 获取当前任务可操作乐西
     *
     * @param task             当前任务
     * @param workflowBusiness 业务数据
     * @return 结果
     */
    private List<String> getTaskHandleType(Task task, WorkflowBusiness workflowBusiness) {
        // 获取当前任务节点
        BpmnModel bpmnModel = repositoryService.getBpmnModel(workflowBusiness.getProcDefId());
        FlowElement flowElement = WorkflowUtils.getFlowElement(task.getTaskDefinitionKey(), bpmnModel);
        // 用户任务
        UserTask userTask = (UserTask) flowElement;
        // 处理类型
        String handleType = userTask.getAttributeValue(WorkflowConstants.NAMASPASE, WorkflowConstants.TASK_HANDLE_TYPE);
        if (StringUtils.isNotEmpty(handleType)) {
            return Arrays.asList(handleType.split(CommonConstants.SPLIT_CHAR_1));
        }
        //拟稿
        if (WorkflowConstants.STATUS_DRAFT.equals(workflowBusiness.getWorkflowStatus())) {
            return Arrays.asList(WorkflowConstants.TASK_TYPE_SUBMIT);
        }
        //第一个节点
        if (WorkflowUtils.checkFirstTaskNode(task.getTaskDefinitionKey(), bpmnModel)) {
            return Arrays.asList(WorkflowConstants.TASK_TYPE_SUBMIT, WorkflowConstants.TASK_TYPE_CANCEL);
        }
        // 委托的任务只能提交
        Map<String, Object> variables = taskService.getVariables(task.getId());
        if (WorkflowUtils.delegateTask(task, variables)) {
            return Arrays.asList(WorkflowConstants.TASK_TYPE_SUBMIT);
        }
        // 判断是否有驳回线
        List<FlowElement> flowElements = WorkflowUtils.findNextElements(task.getTaskDefinitionKey(), bpmnModel, WorkflowConstants.TASK_TYPE_REJECT, variables);
        if (CollectionUtil.isEmpty(flowElements)) {
            return Arrays.asList(WorkflowConstants.TASK_TYPE_SUBMIT, WorkflowConstants.TASK_TYPE_DELEGATE, WorkflowConstants.TASK_TYPE_TURN_TO_DO);
        } else {
            return Arrays.asList(WorkflowConstants.TASK_TYPE_SUBMIT, WorkflowConstants.TASK_TYPE_REJECT, WorkflowConstants.TASK_TYPE_DELEGATE, WorkflowConstants.TASK_TYPE_TURN_TO_DO);
        }
    }


    /**
     * 校验数据
     *
     * @param task          任务
     * @param taskSubmitDto 提交数据
     */
    private void checkData(Task task, TaskSubmitDto taskSubmitDto) {
        if (task == null) {
            throw new WorkflowException("不存在你的任务!");
        }
        //判断是否审批结束
        boolean isEndNode = CommonConstants.YES.equals(taskSubmitDto.getIsEndNode());
        //是否会签节点
        boolean isMulti = CommonConstants.YES.equals(taskSubmitDto.getMultiInstance());
        //提交
        if (WorkflowConstants.TASK_TYPE_SUBMIT.equals(taskSubmitDto.getSubmitType())) {
            // 非结束节点流程审批人必填
            if (!isEndNode && CollectionUtil.isEmpty(taskSubmitDto.getAssignee())) {
                throw new WorkflowException("流程审批人不能为空!");
            }
            //非会签节点流程审批人只能一个
            if (!isMulti && taskSubmitDto.getAssignee().size() > 1) {
                throw new WorkflowException("非会签环节不能多人审批!");
            }
        }
        // 取消
        else if (WorkflowConstants.TASK_TYPE_CANCEL.equals(taskSubmitDto.getSubmitType())) {
            //获取结束节点
            EndEvent endEventNode = flowTaskService.getEndEventNode(task);
            if (endEventNode == null) {
                throw new WorkflowException("不存在结束节点!");
            }
            return;
        }
        // 委托
        else if (WorkflowConstants.TASK_TYPE_DELEGATE.equals(taskSubmitDto.getSubmitType())) {
            if (taskSubmitDto.getAssignee().size() > 1) {
                throw new WorkflowException("非会签环节不能多人审批!");
            }
            return;
        }
        // 转办
        else if (WorkflowConstants.TASK_TYPE_TURN_TO_DO.equals(taskSubmitDto.getSubmitType())) {
            if (taskSubmitDto.getAssignee().size() > 1) {
                throw new WorkflowException("非会签环节不能多人审批!");
            }
            return;
        }
        //判断当前节点与目标节点是否存在关系
        Map<String, Object> variables = taskService.getVariables(task.getId());
        boolean isExistFlow = flowTaskService.checkCurrentToTargetElement(task.getTaskDefinitionKey(), taskSubmitDto.getTargetKey(), task.getProcessInstanceId());
        // 是否委托任务
        if (WorkflowUtils.delegateTask(task, variables) && !task.getTaskDefinitionKey().equals(taskSubmitDto.getTargetKey())) {
            throw new WorkflowException("不存在流程关系!");
        }
        // 非委托任务
        if (!WorkflowUtils.delegateTask(task, variables) && !isExistFlow) {
            throw new WorkflowException("不存在流程关系!");
        }
    }

    /**
     * 处理流程任务
     *
     * @param task          流程任务
     * @param taskSubmitDto 提交信息
     * @param taskType      处理类型
     */
    private void submitWorkflow(Task task, TaskSubmitDto taskSubmitDto, String taskType) {
        Map<String, Object> taskServiceVariables = taskService.getVariables(task.getId());
        Map<String, Object> variables = taskSubmitDto.getVariables();
        //处理任务
        if (WorkflowConstants.TASK_TYPE_SUBMIT.equals(taskType)) {
            if (!CommonConstants.YES.equals(taskSubmitDto.getIsEndNode())) {
                //会签
                if (CommonConstants.YES.equals(taskSubmitDto.getMultiInstance())) {
                    variables.put(WorkflowConstants.USER_TYPE_ASSIGNEE_LIST, taskSubmitDto.getAssignee());
                } else {
                    variables.put(WorkflowConstants.USER_TYPE_ASSIGNEE, CollectionUtil.get(taskSubmitDto.getAssignee(), 0));
                }
            }
            //判断是否委托任务
            if (WorkflowUtils.delegateTask(task, taskServiceVariables)) {
                taskService.resolveTask(taskSubmitDto.getTaskId(), variables);
                //由于委托是在原任务上进行处理，这里需要加一条历史任务来记录委托任务的过程
                addHisTaskInst(task, taskSubmitDto);
                return;
            }
        }
        //添加审批意见
        taskService.addComment(taskSubmitDto.getTaskId(), taskSubmitDto.getInstanceId(), taskType, taskSubmitDto.getComment());
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(taskSubmitDto.getInstanceId())
                .processVariables(variables)
                .moveActivityIdTo(task.getTaskDefinitionKey(), taskSubmitDto.getTargetKey())
                .changeState();
        if (!WorkflowConstants.TASK_TYPE_CANCEL.equals(taskSubmitDto.getSubmitType())) {
            addHisActInstance(task, taskSubmitDto.getTargetKey(), taskSubmitDto);
        }
    }

    /**
     * 添加历史人物审批意见
     *
     * @param historicTaskInstance 任务
     * @param taskSubmitDto        提交参数
     */
    private void addHisTaskComment(HistoricTaskInstanceEntityImpl historicTaskInstance, TaskSubmitDto taskSubmitDto) {
        CommentEntityImpl commentEntity = new CommentEntityImpl();
        commentEntity.setId(IdWorker.get32UUID());
        commentEntity.setTaskId(historicTaskInstance.getId());
        commentEntity.setType(taskSubmitDto.getSubmitType());
        commentEntity.setTime(new Date());
        commentEntity.setUserId(historicTaskInstance.getAssignee());
        commentEntity.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
        commentEntity.setAction(CommentEntity.ACTION_ADD_COMMENT);
        commentEntity.setMessage(taskSubmitDto.getComment());
        commentEntity.setFullMessage(taskSubmitDto.getComment());
        flowTaskService.saveComment(commentEntity);
    }

    /**
     * 封装历史活动记录
     *
     * @param task          任务
     * @param targetKey     目标节点
     * @param taskSubmitDto 提交信息
     */
    private void addHisActInstance(Task task, String targetKey, TaskSubmitDto taskSubmitDto) {
        List<HisActivityInstanceDto> dtoList = new ArrayList<>();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        List<FlowElement> flowElements = WorkflowUtils.getSequenceFlowKey(bpmnModel, task.getTaskDefinitionKey(), targetKey);
        for (FlowElement element : flowElements) {
            HisActivityInstanceDto dto = new HisActivityInstanceDto();
            dto.setRev(1);
            dto.setProcDefId(task.getProcessDefinitionId());
            dto.setProcInstId(task.getProcessInstanceId());
            dto.setExecutionId(task.getExecutionId());
            dto.setActId(element.getId());
            dto.setTaskId(task.getId());
            dto.setActName(element.getName());
            dto.setAssignee(task.getAssignee());
            if (element instanceof SequenceFlow) {
                dto.setActType("sequenceFlow");
            }
            if (element instanceof ExclusiveGateway) {
                dto.setActType("exclusiveGateway");
            }
            if (element instanceof UserTask) {
                dto.setActType("userTask");
            }
            dto.setStartTime(task.getCreateTime());
            dto.setEndTime(new Date());
            dto.setTransactionOrder(2);
            dto.setDuration(dto.getEndTime().getTime() - dto.getStartTime().getTime());
            dto.setDeleteReason(taskSubmitDto.getComment());
            dtoList.add(dto);
        }
        flowTaskService.insertBatchHisActInstance(dtoList);
    }

    /**
     * 历史处理记录
     *
     * @param task          任务
     * @param taskSubmitDto 提交参数
     */
    private void addHisTaskInst(Task task, TaskSubmitDto taskSubmitDto) {
        HistoricTaskInstanceEntityImpl historicTaskInstance = new HistoricTaskInstanceEntityImpl();
        historicTaskInstance.setId(IdWorker.get32UUID());
        historicTaskInstance.setRevision(2);
        historicTaskInstance.setProcessInstanceId(task.getProcessDefinitionId());
        historicTaskInstance.setTaskDefinitionId(task.getTaskDefinitionId());
        historicTaskInstance.setTaskDefinitionKey(task.getTaskDefinitionKey());
        historicTaskInstance.setProcessInstanceId(task.getProcessInstanceId());
        historicTaskInstance.setExecutionId(task.getExecutionId());
        historicTaskInstance.setName(task.getName());
        historicTaskInstance.setOwner(task.getOwner());
        historicTaskInstance.setAssignee(task.getAssignee());
        historicTaskInstance.setStartTime(task.getCreateTime());
        historicTaskInstance.setEndTime(new Date());
        historicTaskInstance.setPriority(50);
        historicTaskInstance.setLastUpdateTime(new Date());
        flowTaskService.insertHisTaskInst(historicTaskInstance);
        // 记录处理意见
        addHisTaskComment(historicTaskInstance, taskSubmitDto);
    }

    /**
     * 流程任务驳回
     *
     * @param taskSubmitDto 流程提交参数
     * @return 成功/失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDto rejectTask(TaskSubmitDto taskSubmitDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.TASK_LOCK_KEY, taskSubmitDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }
        try {
            //获取当前任务
            Task task = taskService.createTaskQuery()
                    .taskId(taskSubmitDto.getTaskId())
                    .taskAssignee(taskSubmitDto.getUserId())
                    .processInstanceId(taskSubmitDto.getInstanceId())
                    .singleResult();
            //校验数据
            checkData(task, taskSubmitDto);
            //设置流程参数
            setTaskParam(task.getId(), taskSubmitDto.getVariables(), WorkflowConstants.TASK_TYPE_REJECT);
            //处理流程任务
            submitWorkflow(task, taskSubmitDto, WorkflowConstants.TASK_TYPE_REJECT);
            // 返回数据
            return buildWorkflowDto(task, this.workflowBusinessService.getWorkflowBusinessByBizId(taskSubmitDto.getBizId()));
        } catch (Exception e) {
            throw new WorkflowException("流程驳回失败:" + e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    /**
     * 流程任务取消/作废
     *
     * @param taskSubmitDto 流程提交参数
     * @return 成功/失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDto cancelTask(TaskSubmitDto taskSubmitDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.TASK_LOCK_KEY, taskSubmitDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }
        //业务流程数据
        WorkflowBusiness workflowBusiness = this.workflowBusinessService.getWorkflowBusinessByBizId(taskSubmitDto.getBizId());
        try {
            //获取当前任务
            Task task = taskService.createTaskQuery()
                    .taskId(taskSubmitDto.getTaskId())
                    .taskAssignee(taskSubmitDto.getUserId())
                    .processInstanceId(taskSubmitDto.getInstanceId())
                    .singleResult();
            //校验数据
            checkData(task, taskSubmitDto);
            //设置流程参数
            setTaskParam(task.getId(), taskSubmitDto.getVariables(), WorkflowConstants.TASK_TYPE_CANCEL);
            //获取结束节点
            EndEvent endEventNode = flowTaskService.getEndEventNode(task);
            taskSubmitDto.setTargetKey(endEventNode.getId());
            //处理流程任务
            submitWorkflow(task, taskSubmitDto, WorkflowConstants.TASK_TYPE_CANCEL);
            workflowBusiness.setWorkflowStatus(WorkflowConstants.STATUS_CANCEL);
            this.workflowBusinessService.updateWorkflowBusiness(workflowBusiness);
            // 返回数据
            return buildWorkflowDto(task, workflowBusiness);
        } catch (Exception e) {
            throw new WorkflowException("流程取消失败:" + e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    /**
     * 查询流程待办任务
     *
     * @param flowTaskQuery 查询参数
     * @return 待办数据
     */
    @Override
    public PageResult<TaskDataDto> findTodo(FlowTaskQuery flowTaskQuery) {
        return flowTaskService.findTodo(flowTaskQuery);
    }

    /**
     * 查询流程已办任务
     *
     * @param flowTaskQuery 查询参数
     * @return 已办数据
     */
    @Override
    public PageResult<TaskDataDto> findDone(FlowTaskQuery flowTaskQuery) {
        return flowTaskService.findDone(flowTaskQuery);
    }

    /**
     * 查询流程审批记录
     *
     * @param bizId 业务id
     * @return 流程记录数据
     */
    @Override
    public List<TaskRecordsDto> findRecords(String bizId) {
        return flowTaskService.findRecords(bizId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDto delegateTask(TaskSubmitDto taskSubmitDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.TASK_LOCK_KEY, taskSubmitDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }
        try {
            //获取任务
            Task task = taskService.createTaskQuery().taskId(taskSubmitDto.getTaskId()).taskAssignee(taskSubmitDto.getUserId()).singleResult();
            //校验数据
            checkData(task, taskSubmitDto);
            //设置任务参数
            setTaskParam(task.getId(), taskSubmitDto.getVariables(), WorkflowConstants.TASK_TYPE_DELEGATE);
            //任务委派
            taskService.delegateTask(taskSubmitDto.getTaskId(), taskSubmitDto.getAssignee().get(0));
            //记录流程处理记录
            this.addHisTaskInst(task, taskSubmitDto);
            this.addHisActInstance(task, task.getTaskDefinitionKey(), taskSubmitDto);
            // 返回数据
            return buildWorkflowDto(task, this.workflowBusinessService.getWorkflowBusinessByBizId(taskSubmitDto.getBizId()));
        } catch (Exception e) {
            throw new WorkflowException("委派任务失败：" + e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    /**
     * 设置任务参数
     *
     * @param taskId     任务id
     * @param param      参数
     * @param submitType 提交类型
     * @return 结果
     */
    private Map<String, Object> setTaskParam(String taskId, Map<String, Object> param, String submitType) {
        //获取任务参数
        Map<String, Object> variables = taskService.getVariables(taskId);
        //其他流程参数
        if (param != null) {
            //设置任务参数
            variables.putAll(param);
        }
        //提交流程
        if (StringUtils.isNotEmpty(submitType)) {
            variables.put(WorkflowConstants.TASK_SUBMIT_TYPE, submitType);
        }
        taskService.setVariables(taskId, variables);
        return variables;
    }

    @Override
    public byte[] readImage(String bizId, HttpServletResponse response) {
        WorkflowBusiness workflowBusiness = workflowBusinessService.getWorkflowBusinessByBizId(bizId);
        try {
            if (workflowBusiness != null) {
                InputStream inputStream = diagramTaskImage(workflowBusiness.getInstanceId());
                return IoUtil.readBytes(inputStream);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WorkflowDto turnToDoTask(TaskSubmitDto taskSubmitDto) {
        //分布式锁key
        String lockKey = StringUtils.format(WorkflowConstants.TASK_LOCK_KEY, taskSubmitDto.getBizId());
        //获取分布式锁
        boolean lockFlag = this.lock.getLock(lockKey);
        if (!lockFlag) {
            return null;
        }
        try {
            //获取任务
            Task task = taskService.createTaskQuery().taskId(taskSubmitDto.getTaskId()).taskAssignee(taskSubmitDto.getUserId()).singleResult();
            //校验数据
            checkData(task, taskSubmitDto);
            //设置任务参数
            setTaskParam(task.getId(), taskSubmitDto.getVariables(), WorkflowConstants.TASK_TYPE_TURN_TO_DO);
            //任务转办
            taskService.setAssignee(taskSubmitDto.getTaskId(), taskSubmitDto.getAssignee().get(0));
            //记录流程处理记录
            this.addHisTaskInst(task, taskSubmitDto);
            this.addHisActInstance(task, task.getTaskDefinitionKey(), taskSubmitDto);
            // 返回数据
            return buildWorkflowDto(task, this.workflowBusinessService.getWorkflowBusinessByBizId(taskSubmitDto.getBizId()));
        } catch (Exception e) {
            throw new WorkflowException("委派任务失败：" + e.getMessage());
        } finally {
            //释放锁
            this.lock.unLock(lockKey);
        }
    }

    @Override
    public boolean withdrawTask(TaskWithdrawDto taskWithdrawDto) {
        //获取业务数据
        WorkflowBusiness business = workflowBusinessService.getWorkflowBusinessByBizId(taskWithdrawDto.getBizId());
        if (business == null) {
            throw new WorkflowException("业务流程数据不存在!");
        }
        if (!business.getCreateUserId().equals(taskWithdrawDto.getUserId())) {
            throw new WorkflowException("不属于你的业务流程数据!");
        }
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(business.getInstanceId())
                .list();
        for (Task task : taskList) {
            //添加审批意见
            taskService.addComment(task.getId(), task.getProcessInstanceId(), WorkflowConstants.TASK_TYPE_WITHDRAW, taskWithdrawDto.getComment());
            taskService.setDueDate(task.getId(), new Date());
        }
        Task task = taskList.get(0);
        // 获取
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(business.getInstanceId())
                .moveActivityIdTo(task.getTaskDefinitionKey(), "applyNode")
                .changeState();
        return true;
    }

    private InputStream diagramTaskImage(String processInstanceId) {
        // 获取当前的流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId;
        // 如果流程已经结束，则得到结束节点
        if (Objects.isNull(processInstance)) {
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {// 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }

        // 获得活动的节点
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();

        List<String> highLightedFlows = new ArrayList<>();
        List<String> highLightedNodes = new ArrayList<>();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        //高亮线
        WorkflowUtils.getHighLightNodeAndFlow(bpmnModel, historicActivityInstances, highLightedFlows, highLightedNodes);

        ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
        //获取自定义图片生成器
        ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
        return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
                configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
    }
}
